package service

import (
	"sync/atomic"

	"xgame.go_server/comm/main_thread"
)

// AsyncBizResult 异步业务结果
type AsyncBizResult[T interface{}] struct {
	// 已返回对象
	returnedObj T
	// 完成回调函数
	completeFunc func()

	// 是否有返回对象
	hasReturnedObj int32
	// 是否有完成回调函数
	hasCompleteFunc int32
	// 是否已经调用过回调函数
	completeFuncHasAlreadyBeenCalled int32
}

// NewAsyncBizResult 创建一个新的异步业务结果, 相当于 new AsyncBizResult().
// 将返回 AsyncBizResult 新对象
func NewAsyncBizResult[T interface{}]() *AsyncBizResult[T] {
	return &AsyncBizResult[T]{
		hasReturnedObj:                   0,
		hasCompleteFunc:                  0,
		completeFuncHasAlreadyBeenCalled: 0,
	}
}

// GetReturnedObj 获取已返回对象
func (this *AsyncBizResult[T]) GetReturnedObj() T {
	return this.returnedObj
}

// PutReturnedObj 设置已返回对象
// val = 已返回对象
func (this *AsyncBizResult[T]) PutReturnedObj(val T) {
	if !atomic.CompareAndSwapInt32(
		&this.hasReturnedObj, 0, 1) {
		// 如果已经设置过返回结果,
		// 就不要重复设置了...
		return
	}

	this.returnedObj = val
	this.tryTodoCompleteFunc()
}

// OnComplete 设置完成回调
// val = 回调函数
func (this *AsyncBizResult[T]) OnComplete(val func()) {
	if nil == val ||
		!atomic.CompareAndSwapInt32(&this.hasCompleteFunc, 0, 1) {
		// 如果已经设置过回调函数,
		// 就不要重复设置了...
		return
	}

	this.completeFunc = val

	if 1 == this.hasReturnedObj {
		// 如果有返回对象,
		this.tryTodoCompleteFunc()
	}
}

// 尝试执行回调函数
func (bizResult *AsyncBizResult[T]) tryTodoCompleteFunc() {
	// 先拿到回调函数,
	// 这样做是为了避免 bizResult.completeFunc 发生改写的风险...
	tempFunc := bizResult.completeFunc

	if nil == tempFunc {
		return
	}

	if atomic.CompareAndSwapInt32(
		&bizResult.completeFuncHasAlreadyBeenCalled, 0, 1) {
		// 扔回到主线程里去执行
		main_thread.Process(tempFunc)
	}
}
